/*
* Copyright (C) 2020 ~ 2023 chaigec All Rights Reserved.
*
* Author:     chaigec <chaigec@163.com>
* Maintainer: chaigec <chaigec@163.com>

 * Use of this source code is governed by MIT license that can be found in the
 * LICENSE file in the root of the source tree. All contributing project authors
 * may be found in the AUTHORS file in the root of the source tree.
*/

#include "MkRtp/MkRtpTcpServer.h"
#include "MkRtp/MkRtpTcpClient.h"
#include "MkEvent/MkEventPool.h"
#include "MkEvent/MkTimer.h"
#include "MkEvent/MkEvent.h"
#include "MkUtil/MkUtil.h"
#include "MkUtil/MkLog.h"
#include "MkUtil/MkLock.h"
#include <gtest/gtest.h>
#ifndef _WIN32
#include "MkUtil/MkMemQueue.h"
#endif

CMkRtpTcpClient *g_pUtRtpClient = nullptr;
CMkLock  g_UtRtpClientLock;
TEST(MkRtpTcpUt, RtpTcpTest)
{
    CMkEventPool* pEventPool = new CMkEventPool;
    pEventPool->Start();
    CMkTimer* pTimer = new CMkTimer;
    pTimer->StartTimerThread();

    Uint16 ServerPort = 0;
    Uint16 ClientPort = 0;
    void* WaitHandle = CreateEvent(nullptr, FALSE, FALSE, nullptr);
    CMkRtpTcpServer *pServer = new CMkRtpTcpServer(pEventPool, pTimer);
    while (1) {
        ServerPort = CMkUtil::GetRandomNumber() % 0xFFFF;
        if (NoneError == pServer->StartServer(ServerPort)) {
            break;
        }
    }
    g_pUtRtpClient = new CMkRtpTcpClient(pEventPool->GetFreeEvent(), pTimer, [WaitHandle](CMkTcpClient* pClient) {
        pClient->DeleteLater();
        g_UtRtpClientLock.Lock();
        g_pUtRtpClient = nullptr;
        g_UtRtpClientLock.Unlock();
        SetEvent(WaitHandle);
    });
    g_UtRtpClientLock.Lock();
    while (1) {
        ClientPort = CMkUtil::GetRandomNumber() % 0xFFFF;
        if (NoneError == g_pUtRtpClient->Start(ClientPort)) {
            break;
        }
    }

    MkRtpRemoter Remoter;
    Remoter.RtpRemoteHost = "127.0.0.1";
    Remoter.RtpRemotePort = ClientPort;
    Remoter.Payload = 100;
    Remoter.RtpType = MkRtpSendRecver;
    Remoter.Ssrc = 123;
    Remoter.RtpPacketCb = [ClientPort](const CMkRtpPacket& RtpPacket, const MkString& Host, Uint16 Port) {
        EXPECT_EQ(Port, ClientPort);
        EXPECT_STREQ("127.0.0.1", Host.c_str());
        EXPECT_EQ(123, RtpPacket.GetSsrc());
        return NoneError;
    };
    pServer->AddRtpRemoter(123, Remoter);



    g_UtRtpClientLock.Unlock();
    MkRtpRemoter ClientRemoter;
    ClientRemoter.RtpRemoteHost = "127.0.0.1";
    ClientRemoter.RtpRemotePort = ServerPort;
    ClientRemoter.Payload = 100;
    ClientRemoter.RtpType = MkRtpSendRecver;
    ClientRemoter.Ssrc = 123;
    ClientRemoter.RtpPacketCb = [ServerPort](const CMkRtpPacket& RtpPacket, const MkString& Host, Uint16 Port) {
        EXPECT_EQ(Port, ServerPort);
        EXPECT_STREQ("127.0.0.1", Host.c_str());
        EXPECT_EQ(123, RtpPacket.GetSsrc());
        return NoneError;
    };
    g_UtRtpClientLock.Lock();
    if (g_pUtRtpClient) {
        g_pUtRtpClient->AddRtpRemoter(123, ClientRemoter);
        g_pUtRtpClient->Connect("127.0.0.1", ServerPort);
    }
    g_UtRtpClientLock.Unlock();
    CMkThread::ThreadSleep(100); //wait connect success
    Uint16 Seq = 1;
    Uint8 pBuf[10] = { 1 };
    CMkRtpPacket RtpPacket;
    RtpPacket.SetPayloadType(100);
    RtpPacket.SetPayloadData(pBuf);
    RtpPacket.SetPayloadLength(10);
    Uint8 pRtpHeader[Len16] = { 0 };
    CMkBufferList BufferList;
    BufferList.Append(pBuf, 10, 1);
    while (Seq < 5) {
        RtpPacket.SetSsrc(123);
        RtpPacket.SetSequenceNumber(Seq);
        RtpPacket.PacketHeader(pRtpHeader, Len16);
        pServer->SendRtpPacket(RtpPacket, "127.0.0.1", ClientPort);

        RtpPacket.SetSsrc(123);
        RtpPacket.PacketHeader(pRtpHeader, Len16);
        g_UtRtpClientLock.Lock();
        if (g_pUtRtpClient) {
            g_pUtRtpClient->SendRtpPacket(RtpPacket, "127.0.0.1", ServerPort);
        }
        g_UtRtpClientLock.Unlock();
        Seq++;
    }
    RtpPacket.SetPayloadData(nullptr);
    RtpPacket.SetPayloadLength(0);
    RtpPacket.SetPayloadBufferList(BufferList);
    while (Seq < 10) {
        RtpPacket.SetSsrc(123);
        RtpPacket.SetSequenceNumber(Seq);
        RtpPacket.PacketHeader(pRtpHeader, Len16);
        pServer->SendRtpPacket(RtpPacket, "127.0.0.1", ClientPort);

        RtpPacket.SetSsrc(123);
        RtpPacket.PacketHeader(pRtpHeader, Len16);
        g_UtRtpClientLock.Lock();
        if (g_pUtRtpClient) {
            g_pUtRtpClient->SendRtpPacket(RtpPacket, "127.0.0.1", ServerPort);
        }

        g_UtRtpClientLock.Unlock();
        Seq++;
    }
    pServer->SendBuffer(BufferList, 123, 400);
    g_UtRtpClientLock.Lock();
    if (g_pUtRtpClient) {
        g_pUtRtpClient->SendBuffer(BufferList, 123, 400);
    }
    g_UtRtpClientLock.Unlock();
    //send app
    CMkRtcpPacket RtcpApp;
    RtcpApp.SetAppSsrc(124);
    RtcpApp.SetAppName(55);
    RtcpApp.SetAppData("test");
    RtcpApp.SetPayload(MkRtcpApp);

    CMkRtcpPacket RtcpApp2;
    RtcpApp2.SetAppSsrc(123);
    RtcpApp2.SetAppName(55);
    RtcpApp2.SetAppData("test");
    RtcpApp2.SetPayload(MkRtcpApp);
    g_UtRtpClientLock.Lock();
    if (g_pUtRtpClient) {
        g_pUtRtpClient->SendRtcpPacket(RtcpApp2, "127.0.0.1", ServerPort + 1);
    }

    g_UtRtpClientLock.Unlock();
    pServer->SendRtcpPacket(RtcpApp, "127.0.0.1", ClientPort + 1);

    //send bye
    CMkRtcpPacket RtcpBye;
    RtcpBye.ByeAddSsrc(124);
    RtcpBye.SetPayload(MkRtcpBye);
    RtcpBye.SetByeReason("send end");

    CMkRtcpPacket RtcpBye2;
    RtcpBye2.ByeAddSsrc(123);
    RtcpBye2.SetByeReason("send end");
    RtcpBye2.SetPayload(MkRtcpBye);
    BOOL bWait = FALSE;
    g_UtRtpClientLock.Lock();
    if (g_pUtRtpClient) {
        g_pUtRtpClient->SendRtcpPacket(RtcpBye2, "127.0.0.1", ServerPort + 1);
        g_pUtRtpClient->DeleteRemoter(124);
        bWait = TRUE;
    }
    g_UtRtpClientLock.Unlock();
    pServer->SendRtcpPacket(RtcpBye, "127.0.0.1", ClientPort + 1);
    pServer->DeleteRemoter(123);
    if (bWait) {
        WaitForSingleObject(WaitHandle, 0xFFFF);
    }

    CloseHandle(WaitHandle);
    pTimer->StopTimerThread();
    pEventPool->Stop();
    MkDelete(pServer);
    MkDelete(pTimer);
    MkDelete(pEventPool);
}